using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using System.Collections.Generic;

namespace IQIGame.Onigao.Game
{
    /// <summary>
    /// 每个模块独立的状态机管理器
    /// </summary>
    public class CFSMModuleManager : IReusableClass
    {
        private ICFSMResLoaderCreater _resLoaderCreater;
        private ICFSMResLoader _resLoader;

        /// <summary>
        /// 按时间帧刷的最小间隔时间，至少间隔N秒才会刷新一次
        /// </summary>
        private float _updateMinInterval;
        private float _updateElapsedTime;
        private float _accumulatedDeltaTime;
        private int _frameInterval;
        private int _elapsedFrame;
        private Dictionary<string, CFSMConfig> _cfgDict = new Dictionary<string, CFSMConfig>();
        private Dictionary<object, ConfigurableFSM> _fsms = new Dictionary<object, ConfigurableFSM>();
        private List<ConfigurableFSM> _tempUpdateFSMs = new List<ConfigurableFSM>();

        public uint MaxStore => 10;
        public bool driveBySelf { get; private set; }
        public bool UpdateByTime => _updateMinInterval > 0;

        public void Init(ICFSMResLoaderCreater resLoaderCreater, bool driveBySelf)
        {
            _resLoaderCreater = resLoaderCreater;
            _resLoader = resLoaderCreater.CreateLoader();
            this.driveBySelf = driveBySelf;
        }

        public void SetInterval(float updateMinInterval)
        {
            this._updateMinInterval = updateMinInterval <= 0 ? 0 : updateMinInterval;
        }

        public void SetInterval(int frameInterval)
        {
            this._frameInterval = frameInterval <= 0 ? 1 : frameInterval;
        }

        public ConfigurableFSM AddFSM(string path, ICFSMEntity entity)
        {
            ConfigurableFSM fsm = ClassPool.Get<ConfigurableFSM>();
            CFSMConfig cfg = GetCfg(path);
            if (cfg == null)
            {
                LogGame.LogError($"添加状态机失败，找不到配置文件：{path}");
                return null;
            }
            fsm.Init(cfg, entity);
            _fsms.Add(entity, fsm);
            return fsm;
        }

        public void RemoveFSM(object entity)
        {
            if (_fsms.Remove(entity, out ConfigurableFSM fsm))
            {
                ClassPool.Put(fsm);
            }
        }

        private CFSMConfig GetCfg(string path)
        {
            if (_cfgDict.TryGetValue(path, out var cfg))
            {
                return cfg;
            }
            var bytes = _resLoader.Load(path);
            if (bytes == null)
            {
                return null;
            }
            ByteBuf buff = new ByteBuf(bytes);
            cfg = new CFSMConfig();
            cfg.DeSerialize(buff);

            _cfgDict.Add(path, cfg);
            return cfg;
        }

        /// <summary>
        /// 刷新
        /// </summary>
        /// <param name="deltaTime"></param>
        public void OnUpdate(float deltaTime)
        {
            _accumulatedDeltaTime += deltaTime;
            if (UpdateByTime)
            {
                if (_updateMinInterval > 0)
                {
                    _updateElapsedTime += deltaTime;
                }
                if (_updateMinInterval <= 0 || _updateElapsedTime >= _updateMinInterval)
                {
                    _updateElapsedTime -= _updateMinInterval;
                    InnerUpdate(_accumulatedDeltaTime);
                    _accumulatedDeltaTime = 0;
                }
            }
            else
            {
                _elapsedFrame++;
                if (_elapsedFrame >= _frameInterval)
                {
                    _elapsedFrame = 0;
                    InnerUpdate(_accumulatedDeltaTime);
                    _accumulatedDeltaTime = 0;
                }
            }
        }

        private void InnerUpdate(float deltaTime)
        {
            _tempUpdateFSMs.Clear();
            foreach (var kv in _fsms)
            {
                _tempUpdateFSMs.Add(kv.Value);
            }
            for (int i = 0; i < _tempUpdateFSMs.Count; i++)
            {
                _tempUpdateFSMs[i].Update(deltaTime);
            }
        }

        public void OnReset()
        {
            _tempUpdateFSMs.Clear();
            foreach (var kv in _fsms)
            {
                ClassPool.Put(kv.Value);
            }
            _fsms.Clear();
            _cfgDict.Clear();
            var resloader = _resLoader;
            _resLoader = null;
            _resLoaderCreater.ReleaseLoader(_resLoader);
            _resLoaderCreater = null;
        }
    }
}
